package com.jx.driving.util;

import java.io.ByteArrayInputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Enumeration;

import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;

/**
 * 简单的加密
 * 
 * @author shenliuyang
 *
 *         2016年8月25日上午10:51:46
 */
public class PassUtils {
	static private final int BASELENGTH = 128;
	static private final int LOOKUPLENGTH = 16;
	static final private byte[] hexNumberTable = new byte[BASELENGTH];
	static final private char[] lookUpHexAlphabet = new char[LOOKUPLENGTH];

	static {
		for (int i = 0; i < BASELENGTH; i++) {
			hexNumberTable[i] = -1;
		}
		for (int i = '9'; i >= '0'; i--) {
			hexNumberTable[i] = (byte) (i - '0');
		}
		for (int i = 'F'; i >= 'A'; i--) {
			hexNumberTable[i] = (byte) (i - 'A' + 10);
		}
		for (int i = 'f'; i >= 'a'; i--) {
			hexNumberTable[i] = (byte) (i - 'a' + 10);
		}

		for (int i = 0; i < 10; i++) {
			lookUpHexAlphabet[i] = (char) ('0' + i);
		}
		for (int i = 10; i <= 15; i++) {
			lookUpHexAlphabet[i] = (char) ('A' + i - 10);
		}
	}

	/**
	 * 加密
	 */
	public static String encrypt(String key, String no, long time) {
		StringBuilder sb = new StringBuilder(no);
		sb.append(key);
		sb.append(time);
		MessageDigest md5;
		try {
			md5 = MessageDigest.getInstance("MD5");
			md5.update(sb.toString().getBytes());
			return DatatypeConverter.printBase64Binary(md5.digest());
		} catch (NoSuchAlgorithmException e) {
			throw new UnsupportedOperationException("不支持md5加密", e);
		}
	}

	public static PrivateKey getDevCAInfo(String key, String pass) throws Exception {
		char[] password = pass.toCharArray();
		byte[] cabuf = DatatypeConverter.parseBase64Binary(key);
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		keyStore.load(new ByteArrayInputStream(cabuf), password);
		Enumeration<String> aliases = keyStore.aliases();
		if (!aliases.hasMoreElements()) {
			throw new RuntimeException("no alias found");
		}
		String alias = aliases.nextElement();
		PrivateKey privatekey = (PrivateKey) keyStore.getKey(alias, password);// 私钥
		return privatekey;
	}

	/**
	 * 获取公钥
	 * 
	 * @param key
	 *            证书
	 * @param pass
	 *            证书密码
	 * 
	 */
	public static X509Certificate getPublicCert(String key, String pass) throws Exception {
		char[] password = pass.toCharArray();
		byte[] cabuf = DatatypeConverter.parseBase64Binary(key);
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		keyStore.load(new ByteArrayInputStream(cabuf), password);
		Enumeration<String> aliases = keyStore.aliases();
		if (!aliases.hasMoreElements()) {
			throw new RuntimeException("no alias found");
		}
		String alias = aliases.nextElement();
		X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
		return cert;
	}

	/**
	 * 加密
	 */
	public static byte[] sign(String data, long timestamp, PrivateKey privateKey) {
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			md.update(data.getBytes("utf-8"));
			md.update(toBE(timestamp));
			byte[] hash = md.digest();
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
			byte[] encrypted = cipher.doFinal(hash);
			return encrypted;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解密
	 */
	public static boolean verify(String data, long timestamp, byte[] encodedEncryptedByte, X509Certificate userCert)
			throws Exception {
		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(data.getBytes("utf-8"));
		md.update(toBE(timestamp));
		byte[] hash = md.digest();
		byte[] encryptedStr = encodedEncryptedByte;
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, userCert);
		byte[] plain = cipher.doFinal(encryptedStr);
		boolean ok = Arrays.equals(hash, plain);
		return ok;
	}

	private static byte[] toBE(long data) {
		byte[] buffer = new byte[4];
		buffer[0] = (byte) (data >>> 24);
		buffer[1] = (byte) (data >>> 16);
		buffer[2] = (byte) (data >>> 8);
		buffer[3] = (byte) (data >>> 0);
		return buffer;
	}

	static public String encode(byte[] binaryData) {
		if (binaryData == null)
			return null;
		int lengthData = binaryData.length;
		int lengthEncode = lengthData * 2;
		char[] encodedData = new char[lengthEncode];
		int temp;
		for (int i = 0; i < lengthData; i++) {
			temp = binaryData[i];
			if (temp < 0)
				temp += 256;
			encodedData[i * 2] = lookUpHexAlphabet[temp >> 4];
			encodedData[i * 2 + 1] = lookUpHexAlphabet[temp & 0xf];
		}
		return new String(encodedData);
	}

	static public byte[] decode(String encoded) {
		if (encoded == null)
			return null;
		int lengthData = encoded.length();
		if (lengthData % 2 != 0)
			return null;

		char[] binaryData = encoded.toCharArray();
		int lengthDecode = lengthData / 2;
		byte[] decodedData = new byte[lengthDecode];
		byte temp1, temp2;
		char tempChar;
		for (int i = 0; i < lengthDecode; i++) {
			tempChar = binaryData[i * 2];
			temp1 = (tempChar < BASELENGTH) ? hexNumberTable[tempChar] : -1;
			if (temp1 == -1)
				return null;
			tempChar = binaryData[i * 2 + 1];
			temp2 = (tempChar < BASELENGTH) ? hexNumberTable[tempChar] : -1;
			if (temp2 == -1)
				return null;
			decodedData[i] = (byte) ((temp1 << 4) | temp2);
		}
		return decodedData;
	}

}
